package com.springboot_blog.utils;

import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 通用对象转换工具类
 * 支持任意对象之间的属性拷贝，以及集合之间的批量转换
 */
public class GeneralConverterUtil {

    /**
     * 将源对象转换为目标类型对象
     * @param source 源对象
     * @param targetClass 目标类型Class
     * @param <T> 目标类型
     * @param <S> 源类型
     * @return 转换后的目标对象
     */
    public static <T, S> T convert(S source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        
        try {
            // 创建目标对象实例
            T target = targetClass.getDeclaredConstructor().newInstance();
            // 拷贝属性
            BeanUtils.copyProperties(source, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("对象转换失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将源对象列表转换为目标类型对象列表
     * @param sourceList 源对象列表
     * @param targetClass 目标类型Class
     * @param <T> 目标类型
     * @param <S> 源类型
     * @return 转换后的目标对象列表
     */
    public static <T, S> List<T> convertList(List<S> sourceList, Class<T> targetClass) {
        if (sourceList == null || sourceList.isEmpty()) {
            return new ArrayList<>(0);
        }
        
        return sourceList.stream()
                .map(source -> convert(source, targetClass))
                .collect(Collectors.toList());
    }

    /**
     * 部分更新目标对象属性（只拷贝源对象中非空的属性）
     * @param source 源对象（包含要更新的属性）
     * @param target 目标对象（被更新的对象）
     * @param <T> 目标对象类型
     * @param <S> 源对象类型
     */
    public static <T, S> void update(T target, S source) {
        if (source == null || target == null) {
            return;
        }
        
        // 获取源对象中值为null的属性名，这些属性不进行拷贝
        String[] ignoreProperties = getNullPropertyNames(source);
        BeanUtils.copyProperties(source, target, ignoreProperties);
    }

    /**
     * 获取对象中值为null的属性名数组
     * @param source 源对象
     * @return null属性名数组
     */
    private static String[] getNullPropertyNames(Object source) {
        org.springframework.beans.BeanWrapper beanWrapper = new org.springframework.beans.BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
        
        List<String> nullPropertyNames = new ArrayList<>();
        for (java.beans.PropertyDescriptor descriptor : propertyDescriptors) {
            String propertyName = descriptor.getName();
            Object propertyValue = beanWrapper.getPropertyValue(propertyName);
            
            if (propertyValue == null) {
                nullPropertyNames.add(propertyName);
            }
        }
        
        return nullPropertyNames.toArray(new String[0]);
    }
}
